import type { Router, RouteRecordRaw, RouterHistory } from 'vue-router'
import { getRouterApi } from '@/api/system/router'
import router from '@/router/index'
import { useMenuStoreHook } from '@/stores/modules/menu'
import { cloneDeep } from 'lodash'
import { isProxy, toRaw } from 'vue'
import { createWebHashHistory, createWebHistory } from 'vue-router'

const adminPrefix = import.meta.env.VITE_ADMIB_PREFIX

/**
 * 根据当前路径获取当前路由信息
 * @param path  当前路径
 * @param routes  路由表
 * @returns RouteRecordRaw
 */
export function findRouteByPath(path: string, routes: RouteRecordRaw[] | readonly RouteRecordRaw[]): RouteRecordRaw {
  let res = routes.find((item: { path: string }) => item.path === path)
  if (res) {
    return isProxy(res) ? toRaw(res) : res
  }
  else {
    for (let i = 0; i < routes.length; i++) {
      const route = routes[i]
      if (!route || !route.children)
        continue

      if (Array.isArray(route.children) && route.children.length > 0) {
        res = findRouteByPath(path, route.children as any)
        if (res) {
          return isProxy(res) ? toRaw(res) : res
        }
      }
    }
  }
  return {} as RouteRecordRaw
}

/**
 * 通过指定 `key` 获取父级路径集合，默认 `key` 为 `path`
 * @param value 当前路径
 * @param routes 路由表
 * @param key 键名
 * @returns string[]
 */
export function getParentPaths(value: string, routes: RouteRecordRaw[], key = 'path'): string[] {
  // 深度遍历查找
  function dfs(routes: RouteRecordRaw[], value: string, parents: string[]) {
    for (let i = 0; i < routes.length; i++) {
      const item: any = routes[i]
      // 返回父级path
      if (item[key] === value)
        return parents
      // children不存在或为空则不递归
      if (!item.children || !item.children.length)
        continue
      // 往下查找时将当前path入栈
      parents.push(item.path)

      if (dfs(item.children, value, parents).length)
        return parents
      // 深度遍历查找未找到时当前path 出栈
      parents.pop()
    }
    // 未找到时返回空数组
    return []
  }

  return dfs(routes, value, [])
}

/**
 * 一维数组处理成多级嵌套数组（三级及以上的路由全部拍成二级，keep-alive 只支持到二级缓存）
 * https://github.com/pure-admin/vue-pure-admin/issues/67
 * @param routesList 处理后的一维路由菜单数组
 * @returns 返回将一维数组重新处理成规定路由的格式
 */
export function formatTwoStageRoutes(routesList: RouteRecordRaw[]) {
  if (routesList.length === 0) {
    return routesList
  }
  const newRoutesList: RouteRecordRaw[] = []
  routesList.forEach((v: RouteRecordRaw) => {
    if (v.path === adminPrefix) {
      newRoutesList.push({
        component: v.component,
        name: v.name,
        path: v.path,
        redirect: v.redirect,
        meta: v.meta,
        children: [],
      })
    }
    else {
      if (newRoutesList[0].children) {
        newRoutesList[0].children.push({ ...v })
      }
    }
  })
  return newRoutesList
}

/**
 * 将多级嵌套路由处理成一维数组
 * @param routesList 传入路由
 * @returns 返回处理后的一维路由
 */
export function formatFlatteningRoutes(routesList: RouteRecordRaw[]) {
  if (routesList.length === 0)
    return routesList
  let hierarchyList = buildHierarchyTree(routesList)
  for (let i = 0; i < hierarchyList.length; i++) {
    if (hierarchyList[i].children) {
      hierarchyList = hierarchyList
        .slice(0, i + 1)
        .concat(hierarchyList[i].children, hierarchyList.slice(i + 1))
    }
  }
  return hierarchyList
}

/**
 * @description 创建层级关系
 * @param tree 树
 * @param pathList 每一项的id组成的数组
 * @returns 创建层级关系后的树
 */
export function buildHierarchyTree(tree: any[], pathList = []): any {
  if (!Array.isArray(tree)) {
    console.warn('tree must be an array')
    return []
  }
  if (!tree || tree.length === 0)
    return []
  for (const [key, node] of tree.entries()) {
    node.id = key
    node.parentId = pathList.length ? pathList[pathList.length - 1] : null
    node.pathList = [...pathList, node.id]
    const hasChildren = node.children && node.children.length > 0
    if (hasChildren) {
      buildHierarchyTree(node.children, node.pathList)
    }
  }
  return tree
}

/**
 * 是否为空，针对 数组、对象、字符串
 * @param obj
 */
function isAllEmpty(obj: any) {
  return obj == null
}

function handRank(routeInfo: any) {
  const { name, path, parentId, meta } = routeInfo
  return isAllEmpty(parentId)
    ? isAllEmpty(meta?.menuRank) || (meta?.menuRank === 0 && name !== 'Home' && path !== adminPrefix)
    : false
}

/** 按照路由中meta下的rank等级升序来排序路由 */
export function ascending(arr: any[]) {
  arr.forEach((v, index) => {
    // 当rank不存在时，根据顺序自动创建，首页路由永远在第一位
    if (handRank(v))
      v.meta.menuRank = index + 2
  })
  return arr.sort(
    (a: { meta: { menuRank: number } }, b: { meta: { menuRank: number } }) => {
      return a?.meta.menuRank - b?.meta.menuRank
    },
  )
}

/** 获取路由模式 */
export function getHistoryMode(routerHistory: string): RouterHistory | undefined {
  // len为1 代表只有历史模式 为2 代表历史模式中存在base参数
  const historyMode = routerHistory.split(',')
  const leftMode = historyMode[0]
  const rightMode = historyMode[1]
  // no param
  if (historyMode.length === 1) {
    if (leftMode === 'hash') {
      return createWebHashHistory('')
    }
    else if (leftMode === 'h5') {
      return createWebHistory('')
    }
  } // has param
  else if (historyMode.length === 2) {
    if (leftMode === 'hash') {
      return createWebHashHistory(rightMode)
    }
    else if (leftMode === 'h5') {
      return createWebHistory(rightMode)
    }
  }
}

/** 从localStorage里取出当前登陆用户的角色roles，过滤无权限的菜单 */
export function filterNoPermissionTree(data: MenuType[]): MenuType[] {
  return filterChildrenTree(data)
}

const modulesRoutes = import.meta.glob('/src/views/**/*.{vue,tsx}')
const IFrame = () => import('@/layout/frameView.vue')

/** 过滤后端传来的动态路由 重新生成规范路由 */
export function addAsyncRoutes(arrRoutes: Array<RouteRecordRaw>): any {
  if (!arrRoutes || !arrRoutes.length)
    return
  const modulesRoutesKeys = Object.keys(modulesRoutes)

  arrRoutes.forEach((v: RouteRecordRaw | any) => {
    // 将backstage属性加入meta，标识此路由为后端返回路由
    v.meta.backstage = true
    // 父级的redirect属性取值：如果子级存在且父级的redirect属性不存在，默认取第一个子级的path；如果子级存在且父级的redirect属性存在，取存在的redirect属性，会覆盖默认值
    if (v?.children && v.children.length && !v.redirect)
      v.redirect = adminPrefix + v.children[0].path
    // 父级的name属性取值：如果子级存在且父级的name属性不存在，默认取第一个子级的name；如果子级存在且父级的name属性存在，取存在的name属性，会覆盖默认值（注意：测试中发现父级的name不能和子级name重复，如果重复会造成重定向无效（跳转404），所以这里给父级的name起名的时候后面会自动加上`Parent`，避免重复）
    if (v?.children && v.children.length && !v.name)
      v.name = `${v.children[0].name as string}Parent`
    if (v.meta?.frameSrc) {
      v.component = IFrame
    }
    else {
      // 对后端传component组件路径和不传做兼容（如果后端传component组件路径，那么path可以随便写，如果不传，component组件路径会跟path保持一致）
      if (!v.children) {
        const index = v?.component
          ? modulesRoutesKeys.findIndex(ev => ev.includes(v.component as any))
          : modulesRoutesKeys.findIndex(ev => ev.includes(v.path))
        v.component = modulesRoutes[modulesRoutesKeys[index]]
      }
    }
    // 默认所有路由在admin下，方便平台做前台
    if (v?.children && v.children.length) {
      addAsyncRoutes(v.children)
    }
  })
  return arrRoutes
}

/** 处理动态路由（后端返回的路由） */
function handleAsyncRoutes(routeList: MenuType[]) {
  if (routeList.length === 0) {
    useMenuStoreHook().handleMenus(routeList)
    return
  }
  // eslint-disable-next-line array-callback-return
  formatFlatteningRoutes(addAsyncRoutes(routeList as RouteRecordRaw[])).map((v: RouteRecordRaw) => {
    if (router.options.routes[0].children) {
      if (router.options.routes[0].children.findIndex(value => value.path === v.path) === -1) {
        // 默认后台路由前缀,方便平台区分前台后台
        v.path = `${adminPrefix}${v.path}`
        router.options.routes[0].children.push(v)
        ascending(router.options.routes[0].children)
        if (!router.hasRoute(v.name as string)) {
          router.addRoute({ ...v })
        }
        const flattenRouters: any = router.getRoutes().find(n => n.path === adminPrefix)
        router.addRoute(flattenRouters)
      }
    }
  })
  useMenuStoreHook().handleMenus(routeList)
  addPathMatch()
}

/** 过滤meta中showLink为false的菜单 */
export function filterTree(data: MenuType[][]) {
  const newTree = Object.assign(data)
    .filter((v: { meta: { showLink: boolean } }) => v.meta?.showLink !== false)
  newTree.forEach((v: { children: any }) => v.children && (v.children = filterTree(v.children)))
  return newTree
}

/** 过滤children长度为0的的目录，当目录下没有菜单时，会过滤此目录，目录没有赋予roles权限，当目录下只要有一个菜单有显示权限，那么此目录就会显示 */
export function filterChildrenTree(data: any) {
  return cloneDeep(data).filter((v: any) => {
    if (v.path === '/admin')
      return true
    return v?.children?.length !== 0
  })
}

/** 添加pathMatch路由，防止路由匹配不到，出现404 */
function addPathMatch() {
  if (!router.hasRoute('pathMatch')) {
    router.addRoute({
      path: '/:pathMatch(.*)',
      name: 'pathMatch',
      redirect: '/404',
    })
  }
}

/** 初始化路由 */
export function initRouter(): Promise<Router> {
  if (useUserStoreHook().accessToken === '') {
    return Promise.resolve(router)
  }
  return new Promise((resolve) => {
    getRouterApi().then(({ data }) => {
      handleAsyncRoutes(filterNoPermissionTree(cloneDeep(data) as any))
      resolve(router)
    })
  })
}
